package com.rran.study.chat.server.netty.server;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rran.study.chat.server.core.repository.ChannelFactory;
import com.rran.study.chat.server.core.repository.ChannelResponsitory;
import com.rran.study.chat.server.core.AcceptInvoke;
import com.rran.study.chat.server.dto.Response;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @author yy
 * @Type WebSocketServerHandler.java
 * @Desc
 * @date 2020/8/6 18:43
 */
@Component
@ChannelHandler.Sharable
@Slf4j
public class WebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> {


    @Autowired
    private AcceptInvoke acceptInvoke;

    /**
     * 描述：读取完连接的消息后，对消息进行处理。
     * 这里主要是处理WebSocket请求
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
        handlerWebSocketFrame(ctx, msg);
    }

    /**
     * 描述：处理WebSocketFrame
     *
     * @param ctx
     * @param frame
     * @throws Exception
     */
    private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
        // 关闭请求
        if (frame instanceof CloseWebSocketFrame) {
            WebSocketServerHandshaker handshaker = ChannelFactory.getWebSocketServerHandshaker(ctx.channel().id().asLongText());
            if (handshaker == null) {
                sendErrorMessage(ctx, "不存在的客户端连接！");
            } else {
                handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            }
            return;
        }
        // ping请求
        if (frame instanceof PingWebSocketFrame) {
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        // 只支持文本格式，不支持二进制消息
        if (!(frame instanceof TextWebSocketFrame)) {
            sendErrorMessage(ctx, "仅支持文本(Text)格式，不支持二进制消息");
        }

        // 客服端发送过来的消息
        String request = ((TextWebSocketFrame) frame).text();
        log.info("服务端收到新信息：" + request);
        JSONObject param = null;
        try {
            param = JSONObject.parseObject(request);
        } catch (Exception e) {
            sendErrorMessage(ctx, "JSON字符串转换出错！");
            e.printStackTrace();
            return;
        }
        if (param == null) {
            sendErrorMessage(ctx, "参数为空！");
            return;
        }
        System.out.println(param);
        Response response = acceptInvoke.invoke(param, ctx);
        if (response != null) {
            ctx.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(response)));
        }
    }

    /**
     * 描述：客户端断开连接
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //清理缓存map
        clear(ctx);
    }

    /**
     * 异常处理：关闭channel
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }


    private void sendErrorMessage(ChannelHandlerContext ctx, String errorMsg) {
        ctx.channel().writeAndFlush(new TextWebSocketFrame(errorMsg));
    }


    private void clear(ChannelHandlerContext ctx) {
        Map<String, ChannelHandlerContext> map = ChannelResponsitory.getChannelMap();
        map.values().removeIf(value -> value == (ctx));
        ChannelResponsitory.removeWebSocketServerHandshaker(ctx.channel().id().asLongText());
        log.info("用户信息:{}", JSON.toJSONString(map));
        log.info("连接信息:{}", JSON.toJSONString(ChannelResponsitory.getWebSocketServerHandshakerMap()));
    }
}
